/**  
 * All rights Reserved, Designed By http://www.pete-cat.com/
 * @Title:  LogInterceptor.java   
 * @Package com.petecat.ruleengine.core.interceptor   
 * @Description:TODO(用一句话描述该文件做什么)   
 * @author: 成都皮特猫科技     
 * @date:2017年12月5日 下午2:30:38   
 * @version V1.0 
 * @Copyright: 2017 www.pete-cat.com Inc. All rights reserved. 
 * 注意：本内容仅限于成都皮特猫信息技术有限公司内部传阅，禁止外泄以及用于其他的商业目
 */  
package com.petecat.ruleengine.core.aop.log;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.ZoneId;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.petecat.ruleengine.core.aop.log.model.LogDataModel;
import com.petecat.ruleengine.core.util.RequestUtils;

/**   
 * @ClassName:  LogAopComp   
 * @Description:日志AOP
 * @author: admin
 * @date:   2017年12月5日 下午2:30:38   
 */
@Component
@Aspect
public class LogAopComp {

	//临时存放对象
	private ThreadLocal<LogDataModel> currentLocalLog = ThreadLocal.withInitial(() -> null);
	
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private Logger vistLogger = LoggerFactory.getLogger("vistLog");
	
	@Pointcut("execution(* com.petecat..*.controller..*.*(..))")
	public void initLog() {
	}
  
	@Before(value="initLog()")
	public void beforeExec(JoinPoint joinPoint) {
		try {
			LogDataModel logDataModel = new LogDataModel();
			HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
			Object[] args =  joinPoint.getArgs();
			//组装输入参数
			if(ArrayUtils.isNotEmpty(args)){
				String inputObjectData = JSON.toJSONString(args);
				logDataModel.setWarpRequestData(inputObjectData);
			}
			String clazz = joinPoint.getTarget().getClass().getName();
			logDataModel.setCls(clazz);
			logDataModel.setMethod(joinPoint.getSignature().getName());
			logDataModel.setType(request.getMethod());
			logDataModel.setRequestData(RequestUtils.getRequestMapForRequest(request));
			logDataModel.setUrlParam(request.getQueryString());
			logDataModel.setExecStartTime(System.nanoTime()/1000000);
			logDataModel.setIp(RequestUtils.getIpAddress(request));
			currentLocalLog.set(logDataModel);
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
	}
	 /**   
	 * @Title: afterExec   
	 * @Description: 正常退出
	 * @param joinPoint
	 * @param rvt
	 * @return void     
	 */
	 @AfterReturning(returning="rvt", pointcut="initLog()")
	 public void afterExec(JoinPoint joinPoint,Object rvt){
		 try {
			LogDataModel dataModel = currentLocalLog.get();
			if (dataModel != null) {
				dataModel.setExecEndTime(System.nanoTime()/1000000);
				if (rvt != null && !rvt.getClass().isAssignableFrom(Void.class)) {
					dataModel.setResult(JSON.toJSONString(rvt));
				}
				this.writerLog(dataModel);
			}
		}catch(Exception e) {
			logger.error(e.getMessage(),e);
		} finally {
			 currentLocalLog.remove();
		}
	 }
	
	 /**   
	 * @Title: writerLog   
	 * @Description: 写日志   
	 * @param dataModel
	 * @return void     
	 */
	private void writerLog(LogDataModel dataModel) {
		vistLogger.info(JSON.toJSONString(dataModel));
	}

	/**   
	 * @Title: afterThrowingExec   
	 * @Description: 异常退出 
	 * @return void     
	 */
	 @AfterThrowing(pointcut="initLog()",throwing="ex")
	 public void afterThrowingExec(JoinPoint joinPoint,Throwable ex){
		 try {
				LogDataModel dataModel = currentLocalLog.get();
				if (dataModel != null) {
					dataModel.setExecEndTime(System.nanoTime()/1000000);
					if (ex != null) {
						StringWriter writer = new StringWriter();
						ex.printStackTrace(new PrintWriter(writer));
						dataModel.setExceptionContent(writer.toString());
					}
					this.writerLog(dataModel);
				}
			}catch(Exception e) {
				logger.error(e.getMessage(),e);
			} finally {
				 currentLocalLog.remove();
			}
	 }
	 
}
